<?php

namespace App\Logic;

use App\Model\ImApply;
use App\Model\ImBlacklist;
use App\Model\ImContact;
use App\Model\ImGroupMessage;
use App\Model\ImMessage;
use App\Model\ImSession;
use App\Model\ImSystem;
use App\Model\User;
use App\Model\UserModelAssist;
use App\Service\SettingService;
use App\Utils\Enum\ImEnum;
use App\Utils\Enum\UserEnum;
use App\Utils\Im;
use App\Websocket\ImWebsocket;
use Exception;
use Hyperf\Context\ApplicationContext;
use Hyperf\DbConnection\Db;
use Hyperf\Redis\Redis;
use Hyperf\WebSocketServer\Sender;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use function Hyperf\Coroutine\co;

class ImLogic
{

    /**
     * 获取会话
     * @param $userid
     * @param bool $withSystem
     * @return array
     */
    public static function getConversation($userid, $withSystem = true): array
    {
        $conversation = [];
        if ($withSystem) {
            $systemMessage = ImSystem::query()->whereIn('userid', [0, $userid])->orderBy('id', 'desc')->first();
            $conversation[] = [
                'userInfo' => [
                    'userNick' => '系统消息',
                ],
                'lastMsg' => [
                    'brief' => $systemMessage ? $systemMessage['msg_title'] : '',
                    'time' => $systemMessage ? $systemMessage['send_time'] : 0,
                ],
                'isSys' => 1,
                'isTop' => 1,
                'unReadNum' => 0,
            ];
        }
        $res = ImSession::where('userid', $userid)->with(['user'])->orderBy('last_msg_time', 'desc')->get()->toArray();
        if (!empty($res)) {
            $targetUserIds = array_column($res, 'to_userid');
            $contactInfo = ImContact::query()->where('userid', $userid)->whereIn('friend_userid', $targetUserIds)->get()->keyBy('friend_userid');
            foreach ($res as $r) {
                $lastMsg = null;
                if ($r['last_msg_id']) {
                    $lastMsg = [
                        'brief' => self::formatBriefMessage($r['last_msg_type'], $r['last_msg_data']),
                        'hasRead' => $userid == $r['last_msg_userid'] ? -1 : $r['last_msg_read'],
                        'time' => $r['last_msg_time'],
                    ];
                }
                $conversation[] = [
                    'sessionId' => $r['session_id'],
                    'userInfo' => [
                        'userId' => $r['user']['id'],
                        'userNick' => isset($contactInfo[$r['to_userid']]) && !empty($contactInfo[$r['to_userid']]['remark_nickname']) ? $contactInfo[$r['to_userid']]['remark_nickname'] : $r['user']['nickname'],
                        'userAvatar' => img_url($r['user']['avatar']),
                        'userRoleId' => $r['user']['role_id'],
                    ],
                    'lastMsg' => $lastMsg,
                    'isSys' => 0,
                    'isTop' => 0,
                    'unReadNum' => $r['unread'],
                ];
            }
        }
        return $conversation;
    }

    /**
     * 获取用户资料
     * @param $userid
     * @param $targetUserId
     * @return array
     * @throws Exception
     */
    public static function getProfile($userid, $targetUserId): array
    {
        $contact = ImContact::query()->where(['userid' => $userid, 'friend_userid' => $targetUserId])->with(['user'])->first();
        if (!$contact) {
            throw new Exception('无权获取该用户资料');
        }
        return [
            'userId' => $contact['user']['id'],
            'imId' => $contact['user']['im_id'],
            'userNick' => $contact['user']['nickname'],
            'remarkNickName' => $contact['remark_nickname'],
            'userAvatar' => img_url($contact['user']['avatar'], 120),
            'isBlackUser' => ImBlacklist::query()->where(['userid' => $userid, 'target_userid' => $targetUserId])->exists()
        ];
    }

    /**
     * 设置昵称
     * @param $userid
     * @param $targetUserId
     * @param $nickname
     * @return true
     * @throws Exception
     */
    public static function setNickName($userid, $targetUserId, $nickname): true
    {
        if (!self::isFriend($userid, $targetUserId)) {
            throw new Exception('TA不是你的好友，不可设置备注昵称');
        }
        ImContact::query()->where(['userid' => $userid, 'friend_userid' => $targetUserId])->update(['remark_nickname' => $nickname]);
        return true;
    }

    /**
     * 获取对话详情
     * @throws Exception
     */
    public static function getChatInfo($userid, $targetUserId): array
    {
        $userInfo = User::query()->where('id', $targetUserId)->select(['id', 'im_id', 'nickname', 'avatar', 'role_id'])->first();
        if (!$userInfo) {
            throw new Exception('该用户不存在');
        }
        if (!ImSession::query()->where(['userid' => $userid, 'to_userid' => $targetUserId])->exists()) {
            throw new Exception('对话不存在');
        }
        $contactInfo = ImContact::query()->where(['userid' => $userid, 'friend_userid' => $targetUserId])->first();
        return [
            'imId' => $userInfo['im_id'],
            'userId' => $userInfo['id'],
            'userNick' => empty($contactInfo['remark_nickname']) ? $userInfo['nickname'] : $contactInfo['remark_nickname'],
            'userAvatar' => img_url($userInfo['avatar'], 48),
            'roleId' => $userInfo['role_id'],
            'isFriend' => ImContact::query()->where(['userid' => $userid, 'friend_userid' => $targetUserId])->exists() ? 1 : 0
        ];
    }

    /**
     * 获取会话消息
     * @param $userId
     * @param $targetUserId
     * @param $input
     * @return array
     */
    public static function getMessageList($userId, $targetUserId, $input): array
    {
        [, $pageSize,] = parsePageParams($input);
        $sessionId = self::createSessionId($userId, $targetUserId);
        $lastId = 0;
        if (!empty($input['msgId'])) {
            $lastId = (int)ImMessage::query()->where('msg_id', $input['msgId'])->first()->value('id');
        }
        $res = ImMessage::query()->where('session_id', $sessionId)->when($lastId, function ($query) use ($lastId) {
            $query->where('id', '<', $lastId);
        })->limit($pageSize)->orderBy('id', 'desc')->get()->toArray();
        $list = [];
        foreach ($res as $r) {
            $list[] = [
                'msgId' => $r['msg_id'],
                'fromUserId' => $r['from_userid'],
                'toUserId' => $r['to_userid'],
                'msgType' => $r['msg_type'],
                'msgData' => $r['msg_data'],
                'hasRead' => $r['has_read'],
                'sendTime' => $r['send_time'],
                'readTime' => $r['read_time'],
            ];
        }
        return $list;
    }

    /**
     * 好友申请
     * @param $userid
     * @param $targetImId
     * @param $targetUserId
     * @param $message
     * @return true
     * @throws Exception
     */
    public static function applyFriend($userid, $targetImId, $targetUserId, $message): true
    {
        if ($userid == $targetUserId) {
            throw new Exception('不能添加自己');
        }
        if (self::isFriend($userid, $targetUserId)) {
            throw new Exception('你们已经是朋友了');
        }
        if (!User::query()->where(['id' => $targetUserId, 'im_id' => $targetImId])->exists()) {
            throw new Exception('用户不存在');
        }
        $targetRoleId = User::query()->where('id', $targetUserId)->value('role_id');
        if ($targetRoleId === UserEnum::USER_TYPE_NORMAL) {
            throw new Exception('不能添加该用户');
        }
        $alreadyApply = ImApply::query()->where(['userid' => $userid, 'to_userid' => $targetUserId, 'status' => ImEnum::APPLY_STATUS_WAIT, 'is_del' => 0])->exists();
        if ($alreadyApply) {
            throw new Exception('你已经向TA发起过申请了，请耐心等待');
        }

        //若对方已向你发起过申请，且为待处理状态，则直接自动同意并成为朋友
        $targetApply = ImApply::query()->where(['userid' => $targetUserId, 'to_userid' => $userid, 'status' => ImEnum::APPLY_STATUS_WAIT, 'is_del' => 0])->orderBy('id', 'desc')->first();
        if ($targetApply) {
            ImApply::query()->where('id', $targetApply['id'])->update([
                'status' => ImEnum::APPLY_STATUS_AGREE,
                'audit_time' => time(),
            ]);
            self::beFriends($userid, $targetUserId);
            throw new Exception('你们已经是朋友啦');
        } else {
            $apply = ImApply::create([
                'userid' => $userid,
                'to_userid' => $targetUserId,
                'message' => $message,
                'status' => ImEnum::APPLY_STATUS_WAIT,
                'apply_time' => time()
            ]);
            if (!$apply) {
                throw new Exception('申请失败');
            }

            //推送
            $userInfo = User::query()->where('id', $userid)->select(['id', 'nickname', 'avatar'])->first();
            co(function () use ($targetUserId, $userInfo) {
                self::pushMessage($targetUserId, '收到新朋友发来的好友申请', [
                    'msgCode' => 'imActionResult',
                    'msgBody' => [
                        'action' => 'friendApply',
                        'data' => new_json_encode([
                            'userId' => $userInfo['id'],
                            'userNick' => $userInfo['nickname'],
                            'userAvatar' => img_url($userInfo['avatar'], 48),
                        ])
                    ],
                ]);
            });
            return true;
        }
    }

    /**
     * 申请列表
     * @param $userid
     * @param $input
     * @return array
     */
    public static function applyList($userid, $input): array
    {
        [, $pageSize, $offset] = parsePageParams($input);
        $total = ImApply::query()->where(function ($query) use ($userid) {
            $query->where('userid', $userid)->orWhere('to_userid', $userid);
        })->where('is_del', 0)->count();
        if ($total) {
            $res = ImApply::query()->where(function ($query) use ($userid) {
                $query->where('userid', $userid)->orWhere('to_userid', $userid);
            })->where('is_del', 0)->with(['user', 'toUser'])->limit($pageSize)->offset($offset)->orderBy('id', 'desc')->get()->toArray();
            $records = [];
            foreach ($res as $r) {
                if ($r['userid'] == $userid) {
                    //发出的
                    $apply = [
                        'userId' => $r['to_userid'],
                        'userNick' => $r['to_user']['nickname'],
                        'userAvatar' => img_url($r['to_user']['avatar'], 48),
                        'userRoleId' => $r['to_user']['role_id'],
                        'isSender' => 1,
                        'isAnchor' => $r['to_user']['role_id'] == UserEnum::USER_TYPE_ANCHOR ? 1 : 0,
                    ];
                } else {
                    //收到的
                    $apply = [
                        'userId' => $r['userid'],
                        'userNick' => $r['user']['nickname'],
                        'userAvatar' => img_url($r['user']['avatar'], 48),
                        'userRoleId' => $r['user']['role_id'],
                        'isSender' => 0,
                        'isAnchor' => $r['user']['role_id'] == UserEnum::USER_TYPE_ANCHOR ? 1 : 0,
                    ];
                }
                $apply['applyTime'] = $r['apply_time'];
                $apply['auditTime'] = $r['audit_time'];
                $apply['status'] = $r['status'];
                $apply['message'] = $r['message'];
                $apply['id'] = $r['id'];
                $records[] = $apply;
            }
        }
        return [
            'total' => $total,
            'pages' => ceil($total / $pageSize),
            'records' => $records ?? []
        ];
    }

    /**
     * 搜索用户
     * @param $userid
     * @param $keyword
     * @return array
     * @throws Exception
     */
    public static function searchUser($userid, $keyword): array
    {
        if (!self::checkMaxSearchTimes($userid)) {
            throw new Exception('超过每日搜索次数限制');
        }
        if (filter_var($keyword, FILTER_VALIDATE_EMAIL)) {
            $field = 'email';
        } elseif (preg_match('/^1\d{10}$/', $keyword)) {
            $field = 'mobile';
        } elseif (preg_match('/^\d+$/', $keyword)) {
            $field = 'im_id';
        } else {
            $field = 'username';
        }

        $records = [];
        $res = User::query()->where($field, $keyword)->select(['id', 'im_id', 'username', 'mobile', 'email', 'nickname', 'avatar', 'role_id'])->get()->toArray();
        if (!empty($res)) {
            $userIds = array_column($res, 'id');
            $friendIds = ImContact::query()->where('userid', $userid)->whereIn('friend_userid', $userIds)->get()->pluck('friend_userid')->toArray();
            foreach ($res as $r) {
                $records[] = [
                    'imId' => $r['im_id'],
                    'userId' => $r['id'],
                    'userName' => $r['username'],
                    'userNick' => $r['nickname'],
                    'userAvatar' => img_url($r['avatar'], 48),
                    'isFriend' => in_array($r['id'], $friendIds) ? 1 : 0,
                ];
            }
        }
        return [
            'total' => count($records),
            'pages' => 1,
            'records' => $records
        ];
    }

    /**
     * 删除会话
     * @param $userid
     * @param $sessionId
     * @return true
     */
    public static function delConversation($userid, $sessionId): true
    {
        ImSession::query()->where(['userid' => $userid, 'session_id' => $sessionId])->delete();
        return true;
    }

    /**
     * 获取通讯录
     * @param $userid
     * @return array
     */
    public static function getContact($userid): array
    {
        $records = [];
        $res = ImContact::where('userid', $userid)->with(['user'])->orderBy('add_time', 'desc')->get()->toArray();
        if (!empty($res)) {
            foreach ($res as $r) {
                $records[] = [
                    'userId' => $r['user']['id'],
                    'userNick' => empty($r['remark_nickname']) ? $r['user']['nickname'] : $r['remark_nickname'],
                    'userAvatar' => img_url($r['user']['avatar'], 48),
                    'userRoleId' => $r['user']['role_id'],
                ];
            }
        }
        return $records;
    }

    /**
     * 备注昵称
     * @param $userid
     * @param $friendUserId
     * @param $nickname
     * @return bool
     */
    public static function remarkNick($userid, $friendUserId, $nickname): bool
    {
        $ret = ImContact::query()->where(['userid' => $userid, 'friend_userid' => $friendUserId])->update(['remark_nickname' => $nickname]);
        return (bool)$ret;
    }

    /**
     * 获取黑名单
     * @param $userid
     * @param $input
     * @return array
     */
    public static function getBlackList($userid, $input): array
    {
        [, $pageSize, $offset] = parsePageParams($input);
        $records = [];
        $total = ImBlacklist::query()->where('userid', $userid)->count();
        if ($total) {
            $res = ImBlacklist::query()->where('userid', $userid)->with('user')->orderBy('id', 'desc')->limit($pageSize)->offset($offset)->get()->toArray();
            foreach ($res as $r) {
                $records[] = [
                    'userId' => $r['user']['id'],
                    'userNick' => $r['user']['nickname'],
                    'userAvatar' => img_url($r['user']['avatar'], 48),
                    'userRoleId' => $r['user']['role_id'],
                    'addTime' => $r['add_time']
                ];
            }
        }
        return [
            'total' => $total,
            'pages' => ceil($total / $pageSize),
            'records' => $records
        ];
    }

    /**
     * 解除拉黑
     * @param $userid
     * @param $targetUserId
     * @return bool
     */
    public static function delBlackUser($userid, $targetUserId): bool
    {
        return (bool)ImBlacklist::query()->where(['userid' => $userid, 'target_userid' => $targetUserId])->delete();
    }

    /**
     * 拉黑
     * @param $userid
     * @param $targetUserId
     * @return true
     * @throws Exception
     */
    public static function setBlackUser($userid, $targetUserId): true
    {
        if ($userid == $targetUserId) {
            throw new Exception('不能拉黑自己');
        }
        if (!User::query()->where('id', $targetUserId)->exists()) {
            throw new Exception('用户不存在');
        }
        if (!ImBlacklist::query()->where(['userid' => $userid, 'target_userid' => $targetUserId])->exists()) {
            ImBlacklist::create([
                'userid' => $userid,
                'target_userid' => $targetUserId,
                'add_time' => time()
            ]);
        }
        return true;
    }

    /**
     * 获取系统消息列表
     * @param $userid
     * @param $input
     * @return array
     */
    public static function sysMsgList($userid, $input): array
    {
        [, $pageSize,] = parsePageParams($input);
        $records = [];
        $res = ImSystem::query()->whereIn('userid', [0, $userid])->when(isset($input['msgId']) && intval($input['msgId']) > 0, function ($query) use ($input) {
            $query->where('id', '<', intval($input['msgId']));
        })->limit($pageSize)->orderBy('id', 'desc')->get()->toArray();
        if (!empty($res)) {
            foreach ($res as $r) {
                $records[] = [
                    'id' => $r['id'],
                    'msgType' => $r['msg_type'],
                    'msgTitle' => $r['msg_title'],
                    'msgTime' => $r['send_time'],
                ];
            }
        }
        return array_reverse($records);
    }

    /**
     * 系统消息详情
     * @param $userid
     * @param $msgId
     * @return array
     * @throws Exception
     */
    public static function sysMsgDetail($userid, $msgId): array
    {
        $msg = ImSystem::query()->where('id', $msgId)->whereIn('userid', [0, $userid])->first();
        if (!$msg) {
            throw new Exception('消息不存在');
        }
        return [
            'title' => $msg['msg_title'],
            'content' => $msg['msg_data'],
            'addTime' => $msg['send_time']
        ];
    }

    /**
     * 处理申请
     * @throws Exception
     */
    public static function doApply($userId, $applyId, $operate): true
    {
        $applyInfo = ImApply::query()->where(['id' => $applyId, 'to_userid' => $userId, 'is_del' => 0])->first();
        if (!$applyInfo) {
            throw new Exception('申请不存在');
        }
        if ($applyInfo['status'] == $operate || $applyInfo['status'] != ImEnum::APPLY_STATUS_WAIT && $operate != ImEnum::APPLY_DO_DELETE) {
            throw new Exception('不可进行此操作');
        }
        if ($operate == ImEnum::APPLY_DO_DELETE) {
            ImApply::query()->where('id', $applyId)->update(['is_del' => 1, 'del_time' => time()]);
        } else {
            ImApply::query()->where('id', $applyId)->update([
                'status' => $operate,
                'audit_time' => time()
            ]);
            if ($operate == ImEnum::APPLY_STATUS_AGREE) {
                self::beFriends($userId, $applyInfo['userid']);
                co(function () use ($applyInfo) {
                    //创建招呼消息
                    $msg1 = self::createMessage($applyInfo['userid'], $applyInfo['to_userid'], ImEnum::MSG_TYPE_SYSTEM, '你们已经是好友了，现在可以开始聊天了');
                    $msg2 = self::createMessage($applyInfo['to_userid'], $applyInfo['userid'], ImEnum::MSG_TYPE_SYSTEM, '你们已经是好友了，现在可以开始聊天了');
                    //推送消息
                    $pushMessage = [
                        'msgCode' => 'ImNewMsgResult',
                        'msgBody' => [
                            'msgId' => $msg1['msg_id'],
                            'userId' => (int)$applyInfo['to_userid'],
                            'msgType' => $msg1['msg_type'],
                            'msgData' => $msg1['msg_data'],
                            'msgTime' => $msg1['send_time'],
                        ],
                    ];
                    self::pushMessage($applyInfo['userid'], '您收到一条新消息', $pushMessage);
                    $pushMessage['msgBody']['msgId'] = $msg2['msg_id'];
                    $pushMessage['msgBody']['userid'] = (int)$applyInfo['userid'];
                    self::pushMessage($applyInfo['to_userid'], '您收到一条新消息', $pushMessage);
                });
            }
        }
        return true;
    }

    /**
     * 创建消息
     * @throws Exception
     */
    public static function createMessage($fromUserId, $toUserId, $msgType, $msgData, $msgId = '', $hideFrom = false): array
    {
        if (empty($msgId)) {
            $msgId = create_randomstr(10);
        }
        $sessionId = self::createSessionId($fromUserId, $toUserId);
        $msg = ImMessage::create([
            'msg_id' => $msgId,
            'session_id' => $sessionId,
            'from_userid' => $fromUserId,
            'to_userid' => $toUserId,
            'msg_type' => $msgType,
            'msg_data' => $msgData,
            'send_time' => time()
        ]);
        if (!$msg) {
            throw new Exception('消息创建失败');
        }
        $lastMsg = [
            'last_msg_id' => $msg['msg_id'],
            'last_msg_type' => $msg['msg_type'],
            'last_msg_data' => $msg['msg_data'],
            'last_msg_userid' => $fromUserId,
            'last_msg_read' => 0,
            'last_msg_time' => $msg['send_time'],
        ];
        $session = ImSession::query()->where('session_id', $sessionId)->get()->keyBy('userid');
        foreach ([$fromUserId, $toUserId] as $i => $userid) {
            if ($i == 0 && $hideFrom) {
                continue;
            }
            if (isset($session[$userid])) {
                $update = $userid == $toUserId ? array_merge($lastMsg, ['unread' => Db::raw('`unread` + 1')]) : $lastMsg;
                ImSession::query()->where('id', $session[$userid]['id'])->update($update);
            } else {
                ImSession::create([
                        'session_id' => $sessionId,
                        'userid' => $userid,
                        'to_userid' => $i ? $fromUserId : $toUserId,
                        'unread' => $userid == $toUserId ? 1 : 0,
                    ] + $lastMsg);
            }
        }
        return $msg->toArray();
    }

    /**
     * 成为朋友
     * @param $userid
     * @param $targetUserId
     * @return true
     * @throws Exception
     */
    public static function beFriends($userid, $targetUserId): true
    {
        Db::beginTransaction();
        $ret1 = ImContact::create([
            'userid' => $userid,
            'friend_userid' => $targetUserId,
            'remark_nickname' => '',
            'add_time' => time()
        ]);
        $ret2 = ImContact::create([
            'userid' => $targetUserId,
            'friend_userid' => $userid,
            'remark_nickname' => '',
            'add_time' => time()
        ]);
        if ($ret1 && $ret2) {
            Db::commit();
            //TODO 通知$targetUserId新增好友
            return true;
        } else {
            Db::rollBack();
            throw new Exception('成为朋友失败');
        }
    }

    /**
     * 是否是朋友关系
     * @param $userid
     * @param $targetUserId
     * @return bool
     */
    public static function isFriend($userid, $targetUserId): bool
    {
        return ImContact::query()->where([['userid', '=', $userid], ['friend_userid', '=', $targetUserId]])->orWhere([['friend_userid', '=', $targetUserId], ['userid', '=', $userid]])->exists();
    }

    /**
     * 是否是助理对话
     * @param $userid
     * @param $targetUserId
     * @return bool
     */
    public static function isAssistChat($userid, $targetUserId): bool
    {
        return UserModelAssist::query()->where('userid', $userid)->orWhere('userid', $targetUserId)->exists();
    }

    /**
     * 获取未读消息数
     * @param $userid
     * @return int
     */
    public static function getUnreadMsgNum($userid): int
    {
        return ImSession::query()->where('userid', $userid)->sum('unread');
    }

    /**
     * 获取未处理好友请求数
     * @param $userid
     * @return int
     */
    public static function getUnDoApplyNum($userid): int
    {
        return ImApply::query()->where(['to_userid' => $userid, 'status' => 0])->count();
    }

    /**
     * 从sessionId中获取对话用户ID
     * @param $sessionId
     * @param $userid
     * @return int
     */
    public static function getTargetUserId($sessionId, $userid): int
    {
        $sessionInfo = ImSession::query()->where('id', $sessionId)->select(['id', 'userid', 'to_userid'])->first();
        if (!$sessionInfo || $userid != $sessionInfo['userid'] && $userid != $sessionInfo['to_userid']) {
            return 0;
        }
        return $sessionInfo['userid'] == $userid ? $sessionInfo['to_userid'] : $sessionInfo['userid'];
    }

    /**
     * 获取群聊消息
     * @param $groupId
     * @param $msgNum
     * @param $lastMsgId
     * @return array
     */
    public static function getGroupLastMsg($groupId, $msgNum = 30, $lastMsgId = 0): array
    {
        if (!preg_match('/^\d+$/', $lastMsgId)) {
            $lastMsgId = ImGroupMessage::query()->where('msg_id', $lastMsgId)->value('id');
            if (!$lastMsgId) {
                return [];
            }
        }
        $list = ImGroupMessage::query()->where('group_id', $groupId)->when(intval($lastMsgId) > 0, function ($query) use ($lastMsgId) {
            $query->where('id', '<', $lastMsgId);
        })->orderBy('id', 'desc')->limit($msgNum)->get()->toArray();
        $records = [];
        foreach ($list as $r) {
            $records[] = [
                'msgId' => $r['msg_id'],
                'userId' => $r['userid'],
                'userNick' => $r['user_nick'],
                'userType' => $r['user_type'],
                'userLevel' => $r['user_level'],
                'msgType' => $r['msg_type'],
                'msgData' => $r['msg_data'],
                'msgTime' => $r['send_time']
            ];
        }
        return $records;
    }

    /**
     * 获取备注昵称
     * @param $userid
     * @param $friendUserId
     * @return string
     */
    public static function getFriendRemarkNickName($userid, $friendUserId): string
    {
        return (string)ImContact::query()->where(['userid' => $userid, 'friend_userid' => $friendUserId])->value('remark_nickname');
    }

    /**
     * 创建SessionId
     * @param ...$userIds
     * @return false|string
     */
    public static function createSessionId(...$userIds): false|string
    {
        if (empty($userIds)) {
            return false;
        }
        sort($userIds);
        return implode('-', $userIds);
    }

    /**
     * 消息简要
     * @param $msgType
     * @param $msgData
     * @return string
     */
    public static function formatBriefMessage($msgType, $msgData): string
    {
        switch ($msgType) {
            case ImEnum::MSG_TYPE_LINK:
            case ImEnum::MSG_TYPE_SYSTEM:
                return $msgData;
            case ImEnum::MSG_TYPE_TEXT:
                return trim(strip_tags($msgData));
            case ImEnum::MSG_TYPE_IMAGE:
                return '[图片]';
            case ImEnum::MSG_TYPE_VOICE:
                return '[语音消息]';
            case ImEnum::MSG_TYPE_VIDEO:
                return '[视频消息]';
            case ImEnum::MSG_TYPE_CONTACT:
                return '[名片消息]';
            case ImEnum::MSG_TYPE_LOCATION:
                return '[位置消息]';
            case ImEnum::MSG_TYPE_WELCOME:
                return '新朋友加入了群聊';
            case ImEnum::MSG_TYPE_RED_PACKET:
                return '[红包]';
            default:
                return '';
        }
    }

    /**
     * 消息推送
     * @param $userid
     * @param $title
     * @param $payload
     * @return bool
     */
    public static function pushMessage($userid, $title, $payload): bool
    {
        $container = ApplicationContext::getContainer();
        try {
            $imWS = $container->get(ImWebsocket::class);
            $fd = $imWS->getFdByUid($userid);
            if ($fd) {
                $sender = $container->get(Sender::class);
                $sender->push($fd, Im::Create($payload['msgCode'], $payload['msgBody']));
            } else {
                //TODO 离线通知
            }
            return true;
        } catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
            return false;
        }
    }

    /**
     * 创建消息ID
     * @return string
     */
    public static function createMsgId(): string
    {
        return create_randomstr(15);
    }

    /**
     * 生成聊天ID
     * @return int
     */
    public static function createImID(): int
    {
        static $setting;
        if (is_null($setting)) {
            $setting = SettingService::getGroupSetting('im');
            $setting['im_reserve_ids'] = array_unique(array_filter(explode(',', trim($setting['im_reserve_ids']))));
        }
        $ID = mt_rand(1, 9) . random(intval($setting['im_id_length']) - 1);
        if (in_array($ID, $setting['im_reserve_ids']) || User::query()->where('im_id', $ID)->exists()) {
            return self::createImID();
        }
        return (int)$ID;
    }

    /**
     * 删除好友
     * @param $userId
     * @param $targetUserId
     * @return true
     */
    public static function delFriend($userId, $targetUserId): true
    {
        $sessionId = self::createSessionId($userId, $targetUserId);
        ImMessage::query()->where('session_id', $sessionId)->delete();
        ImContact::query()->where(['userid' => $userId, 'friend_userid' => $targetUserId])->delete();
        ImContact::query()->where(['userid' => $targetUserId, 'friend_userid' => $userId])->delete();
        ImSession::query()->where('session_id', $sessionId)->delete();
        ImApply::query()->where(['userid' => $userId, 'to_userid' => $targetUserId])->delete();
        ImApply::query()->where(['userid' => $targetUserId, 'to_userid' => $userId])->delete();
        return true;
    }

    /**
     * 检查搜索用户是否超限
     * @param $userid
     * @return bool
     */
    private static function checkMaxSearchTimes($userid): bool
    {
        try {
            $maxSearchTimes = (int)SettingService::get('im_max_search_times', 0);
            $key = 'im:search:' . $userid;
            $redis = ApplicationContext::getContainer()->get(Redis::class);
            $times = $redis->incr($key);
            if ($times == 1) {
                $redis->expire($key, mktime(0, 0, 0, date('m'), (int)date('d') + 1) - time());
            }
            if ($maxSearchTimes && $times > $maxSearchTimes) {
                return false;
            }

        } catch (NotFoundExceptionInterface|ContainerExceptionInterface|\RedisException $e) {
        }
        return true;
    }
}